<template>
  <div id="container" ref="mycanvas" @contextmenu.prevent="onMouseDown"></div>
</template>

<script>
import * as THREE from "three";
import { OBJLoader, MTLLoader } from "three-obj-mtl-loader";
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { SceneUtils } from 'three/examples/jsm/utils/SceneUtils.js'
import { TransformControls } from 'three/examples/jsm/controls/TransformControls'
import { DragControls } from 'three/examples/jsm/controls/DragControls'
export default {
  data() {
    return {
      /**场景 */
      scene: null,
      /**相机 */
      camera: null,
      /**渲染 */
      renderer: null,
      /**控制器 */
      controls: null,
      /**屋顶 */
      roof: null, 
      requestId: null,
      /**容器 */
      container: null,
      transformControls: '',
      firstClick:true,
      pointsArray:[],
      array:[],
      window_mouse:true,
      end:[]
    };
  },
  methods: {
    /**初始化 */
    initScene() {
      this.scene = new THREE.Scene();
      // 环境光：
      const ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
      this.scene.add(ambientLight);
      // 辅助坐标系：
      var axisHelper = new THREE.AxisHelper(50);
      this.scene.add(axisHelper);
      // //网格辅助线：
      // var helper = new THREE.GridHelper(1080, 1080, 0xCD3700, 0x4A4A4A);
      // this.scene.add(helper);
    },
    initCamera() {
      this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
      this.camera.position.set(0, 20, 30);
      this.camera.lookAt(new THREE.Vector3(0, 0, 0));
    },
    initLight(){
      var ambientLight = new THREE.AmbientLight(0x333333);
      this.scene.add(ambientLight);

      var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
      directionalLight.position.set(100, 300, 200);
      this.scene.add(directionalLight);
    },
    //渲染器render初始化:
    initRenderer() {
      this.renderer = new THREE.WebGLRenderer({antialias: true});
      this.renderer.setSize(window.innerWidth, window.innerHeight);
      this.container = document.getElementById("container");
      container.appendChild(this.renderer.domElement);
      // console.log("renderer",this.renderer)
    },
    initControl() {
      // 鼠标控制
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      // this.controls.target = new THREE.Vector3(0, 0, 0);
      // // 视角最小距离
      // this.controls.minDistance = 12;
      // // 视角最远距离
      // this.controls.maxDistance = 100;
      // // 最大角度
      // this.controls.maxPolarAngle = Math.PI/4;
    },
    /* 获取射线与平面相交的交点 */
    getIntersects(event) {
      event.preventDefault();
      var vector = new THREE.Vector3();// 三维坐标对象
      // 通过鼠标点击位置,计算出 raycaster 所需点的位置,以屏幕为中心点,范围 -1 到 1
      vector.set((event.clientX / this.renderer.domElement.clientWidth) * 2 - 1,-((event.clientY -60)/ this.renderer.domElement.clientHeight) * 2 + 1, 0.5);
      // 通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
      vector.unproject(this.camera);
      var raycaster = new THREE.Raycaster(this.camera.position, vector.sub(this.camera.position).normalize());
      // 获取与射线相交的对象数组，其中的元素按照距离排序，越近的越靠前
      var intersects = raycaster.intersectObjects(this.scene.children, true);

      // 返回选中的对象
      return intersects;
    },
    /* 鼠标按下事件 */
    onMouseDown(event) {
        /* 获取相机发出的射线与 Plane 相交点*/
        var intersects = this.getIntersects(event);
        if (event.button === 0) {
            console.log("鼠标左键点击了")
            console.log("交点",intersects);
            if (this.window_mouse===false){
                window.addEventListener('mousemove', this.onMouseMove, false);
                /* 依据 windwo_mouse 标识避免事件的重复添加 */
                this.window_mouse = true;
            }
            if (intersects.length>0) {
              /* 创建点（Points） */
              this.drawPoints(intersects[0].point);

              if (this.firstClick) {
                this.end = this.pointsArray.slice(-1);
                this.firstClick = false;
              }
              /* 创建线段 */
              if (this.end.length >0) {
                  this.drawLine(this.end[0].geometry.attributes.position.array,intersects[0].point,false);
                  //记录本轮最后一个点，作为下一次画线的起始点：
                  this.end = this.pointsArray.slice(-1);
                  this.array.shift();
                  this.pointsArray.shift();
              }
            }
        }else if (event.button === 2) {
        /* 鼠标右键按下时 回退到上一步的点，并中断绘制 */
            console.log("鼠标右键点击了")
            console.log("交点",intersects);
            // /* 绘制结束，移除鼠标点击和移动事件 */
            window.removeEventListener('mousemove', this.onMouseMove, false);
            this.window_mouse = false;
            window.removeEventListener('click', this.onMouseDown, false);

            // /* 移除事件之后，要设置为 false 为了避免事件的重复添加 */
            this. window_mouse = false;
            // /* 取出点 */
            let points = [];
            this.scene.traverse(function (object) {
                if (object.isPoints) {
                    points.push(object);
                }
            });
            console.log("所有点：",points);
            if (points.length>2) {//生成围栏：
              var shape = new THREE.Shape(this.conv2Vector2(points));
              var geometry = new THREE.ExtrudeGeometry(//拉伸造型
                  shape,//二维轮廓
                  //拉伸参数
                  {
                      amount:-10,//拉伸长度
                      bevelEnabled:false//无倒角
                  });
              console.log("拉伸对象",geometry);
              var map1 = new THREE.ImageUtils.loadTexture( '/static/UXSINO_CD/tex/border.png' );
              map1.wrapS = map1.wrapT = THREE.RepeatWrapping; // CHANGED
              map1.offset.set( 0, 0.5 ); // CHANGED
              map1.repeat.set( 0.01, 0.01 ); // CHANGED
              // var material = new THREE.MeshBasicMaterial({
              //     // color: 0x0000ff,
              //     // opacity:0.7,//透明度0完全透明-1不透明
              //     // transparent:true,//是否开启透明，默认false
              //     map: map1,
              //     side: THREE.DoubleSide //两面可见
              // });
                // 创建材质  顶面
              let boxMaterial = new THREE.MeshBasicMaterial({
                  color: 0x45006f,
                  opacity:0,//透明度0完全透明-1不透明
                  transparent:true,//是否开启透明，默认false
              });
                // 再创建材质 侧面
              let boxMaterialB = new THREE.MeshBasicMaterial({
                  opacity:0.7,
                  map: map1,
                  side: THREE.DoubleSide //两面可见
              });
              var materials = [boxMaterial, boxMaterialB]; 
              var mesh=new THREE.Mesh(geometry,materials);//模型对象
              mesh.receiveShadow = true; 
              mesh.rotateX(Math.PI/2);
              mesh.position.set(0,0,0);
              this.scene.add( mesh );
            }
            // /* 鼠标左键未点击时线段的移动状态 */
            if (this.scene.getObjectByName('line_move')) {
                this.scene.remove(this.scene.getObjectByName('line_move'));
                /* 删除数组中的元素，否则的话再次重绘会链接之前的点接着重绘 */
                this.pointsArray.shift();

            }
            this.deleteLast();/* 删除最后的点和线，并恢复鼠标点击和键盘事件 */
        }
    },
    drawPoints(intersects){
      /* 若交点此时在平面之内则创建点（Points） */
        var material = new THREE.PointsMaterial( { color: 0xff0000,size: 1 } );
        var vertices = [];
        vertices.push( intersects );
        var geometry = new THREE.BufferGeometry().setFromPoints( vertices );
        var point = new THREE.Points( geometry, material );
        // var array = [];
        this.array.push(point);
        
        this.pointsArray = this.array;

        // console.log("画点时array",this.array);
        // console.log("画点时pointsArray",this.pointsArray);
        // this.pointsArray.push(point);
        this.scene.add(point)
    },
    drawLine(vertice1,vertice2,isMove){
      var lineMaterial = new THREE.LineBasicMaterial( { color: 0x00ff00 } );
      var lineVertices = [];
      lineVertices.push( new THREE.Vector3(vertice1[0],vertice1[1],vertice1[2]) );
      lineVertices.push( new THREE.Vector3(vertice2.x,vertice2.y,vertice2.z) );
      var lineGeometry = new THREE.BufferGeometry().setFromPoints( lineVertices );
      var line = new THREE.LineLoop( lineGeometry, lineMaterial );
      if(isMove){
        line.name = 'line_move';
      }else{
        line.name = 'line_click';
      }
      this.scene.add(line);
    },
    /* 当创建完一个电子围栏后执行删除操作 */
    deleteLast() {
        console.log('结束！');
        for (let i = 0; i < this.scene.children.length; i++) {
            let object = this.scene.children[i];
            // if ((object.type === "Points") || (object.type === "Line")) {
            if (object.isLine || object.isPoints){
                this.scene.remove(object);
                /* i-- 作用：用来控制scene.children.length不断减小而 i 却不断变大的问题，否则会导致无法完全删除元素 */
                i--;
            }
        }
        this.end=[];
        this.firstClick=true;
        this.array=[];
        this.pointsArray=[];
        /* 移除完线段、点、球结束后 再次添加点击事件 */
         window.addEventListener('click', this.onMouseDown, false);
        /* 动画结束之后， 在添加键盘事件 */
         window.addEventListener('keydown', this.onKeyDown, false);
   },
    /* 鼠标移动事件 */
    onMouseMove(event) {
        var intersects = this.getIntersects(event);
        /* 鼠标左键未点击时线段的移动状态 */
        if (this.scene.getObjectByName('line_move')) {
            this.scene.remove(this.scene.getObjectByName('line_move'));
        }
        /* 创建线段 */
        if (this.end.length > 0 && intersects.length>0) {
          // this.drawLine(this.pointsArray[0].geometry.attributes.position.array,intersects[0].point,true);
          this.drawLine(this.end[0].geometry.attributes.position.array,intersects[0].point,true);
        }
    },
    /* 键盘按下事件 */
    onKeyDown(event) {
        /* ESC键 回退上一步绘制，结束绘制*/
        if (event.key === 'Escape'){
            window.removeEventListener('mousemove', this.onMouseMove, false);
            /* 移除事件之后，要设置为 false 为了避免 mousemove 事件的重复添加 */
            this.window_mouse = false;
            this.end=[];
            this.firstClick=true;
            /* 鼠标左键未点击时线段的移动状态 */
            if (this.scene.getObjectByName('line_move')) {
                this.scene.remove(this.scene.getObjectByName('line_move'));
                /* 删除数组中的元素，否则的话再次重绘会链接之前的点接着重绘 */
                this.array.shift();
                this.pointsArray.shift();
            }
            var length = this.scene.children.length - 1;
            /* 按步骤移除点和先 */
            if (this.scene.children[length].isLine || this.scene.children[length].isPoints){
                this.scene.children.pop();
                length = this.scene.children.length - 1;
                /* 若最后一项不是线段或者点就不移除 */
                if (!this.scene.children[length].isMesh) {
                    this.scene.children.pop();
                }
            }
        }
    },
    //vector3转化成vector2:
    conv2Vector2(points){
        var temp = [];
        var j;
        for (var i = 0; i < points.length; i++) {
            if (i == points.length-1) {
                temp.push(new THREE.Vector2(points[0].geometry.attributes.position.array[0],points[0].geometry.attributes.position.array[2]));
            }else{
                temp.push(new THREE.Vector2(points[i].geometry.attributes.position.array[0],points[i].geometry.attributes.position.array[2]));
            }
            j = i;
        }
        var item = new THREE.Vector2(points[j].geometry.attributes.position.array[0],points[j].geometry.attributes.position.array[2]);
        temp[j]=item;
        console.log("j",j);
        console.log("temp",temp);
        return temp;
    },



    //渲染:
    animate() {
      // this.requestId = requestAnimationFrame(this.animate);
      // this.renderer.render(this.scene, this.camera);
      // this.controls.update()
      requestAnimationFrame(this.animate);
      this.renderer.render(this.scene, this.camera);
      this.controls.update();
      
    },
    init() {
      this.initScene();
      this.initCamera();
      this.initRenderer();
      this.initLight();
      this.initControl();

      /* 事件监听 */
      window.addEventListener('click', this.onMouseDown, false);
      // window.addEventListener('mousedown', this.onMouseDown, false);/* 使用mousedown的时候可以判断出点击的鼠标左右键之分 */
      window.addEventListener('mousemove', this.onMouseMove, false);
      window.addEventListener('keydown', this.onKeyDown, false);/* 使用事件的时候要把前面的on给去掉 */
      window.addEventListener('resize', this.onWindowResize, false);

    },
    /**加载模型 */
    loadPlant() {
      let that = this;

      let objLoader = new OBJLoader();//obj模型加载器
      let mtlLoader = new MTLLoader();//材质文件加载器
      mtlLoader.load("/static/UXSINO_CD/UXSINO_CD.mtl", function(materials) {
        // materials.preload();
        objLoader.setMaterials(materials);//obj模型会和MaterialCreator包含的材质对应起来
        objLoader.load(
          "/static/UXSINO_CD/UXSINO_CD.obj",
          function(obj) {
            obj.position.set(0, 0, 0);//模型摆放的位置
            obj.scale.set(0.03, 0.03, 0.03);//模型放大或缩小的系数
            that.scene.add(obj);//将模型加入场景中
            // console.log("time："+(new Date().getTime() / 1000) - that.a + " s")
          },
          // called while loading is progressing
          function(xhr) {
            console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
          },
          // called when loading has errors
          function(error) {
            console.log("An error happened");
          }
        );
      });
    },
    onResize() {
      this.camera.aspect = window.innerWidth;  //宽高可根据实际项目要求更改 如果是窗口高度改为innerHeight
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(window.innerWidth, window.innerWidth);  //宽高可根据实际项目要求更改 如果是窗口高度改为innerHeight
      // this.camera.aspect = window.innerWidth / 1080;  //宽高可根据实际项目要求更改 如果是窗口高度改为innerHeight
      // this.camera.updateProjectionMatrix();
      // this.renderer.setSize(window.innerWidth, 1080);  //宽高可根据实际项目要求更改 如果是窗口高度改为innerHeight
    }
  },
  mounted() {
    this.init();
    this.loadPlant();
    this.animate();
    document.getElementsByTagName("canvas")[0].style.verticalAlign = "bottom"; //解决canvas底部留白问题
    window.addEventListener("resize", this.onResize, false);
  }
  // destroyed() {
  //   cancelAnimationFrame(this.requestId);
  //   this.scene = null;
  //   this.camera = null;
  //   this.renderer = null;
  //   this.controls = null;
  //   // window.removeEventListener("resize", this.onResize, false);
  // }
};
</script>

<style scoped>
#container {
  height: 1080px;
}
</style>